#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <openssl/md5.h>
#define MAX_PATH 256
#define MAX_LINE_LEN 512
#define MD5_UNIT (1<<12)
#define STR_EQUAL(s1,s2) (strcmp(s1,s2)==0)

unsigned char* convert_to_md5(unsigned char* buf)
{
	unsigned char md5[16];
	MD5(buf, MD5_UNIT, md5);
	strcpy((char*)buf, (char*)md5);
	buf[16] = '\0';
	return buf;
}

int is_same_md5(unsigned char* base, unsigned char* ref)
{
	return !strcmp((char*)convert_to_md5(base), (char*)convert_to_md5(ref)) ? 1 : 0;
}

int is_same_file(const char* base, const char* ref)
{
	int ret = 1;
	int rd_len_base, rd_len_ref;
	unsigned char buf_base[MD5_UNIT];
	unsigned char buf_ref[MD5_UNIT];
	int fd_base = open(base, O_RDONLY);
	int fd_ref = open(ref, O_RDONLY);

	if (fd_base <= 0 || fd_ref <= 0) ret = 0; 
	else {
		do {
			memset(buf_base, 0, MD5_UNIT);
			memset(buf_ref, 0, MD5_UNIT);
			rd_len_base = read(fd_base, buf_base, MD5_UNIT);
			rd_len_ref = read(fd_ref, buf_ref, MD5_UNIT);
			if (rd_len_base != rd_len_ref) ret = 0;
			else if (!is_same_md5(buf_base, buf_ref)) ref = 0; 
		} while(ref && rd_len_base==MD5_UNIT && rd_len_ref==MD5_UNIT);
	}

	if (fd_base) close(fd_base);
	if (fd_ref) close(fd_ref);
	return ret;
}

void compose_path(char* new_path, const char* dir, const char* last)
{
	memset(new_path, 0, MAX_PATH);
	strcat(new_path, dir);
	strcat(new_path, "/");
	strcat(new_path, last);
}

int is_sub_dir(const char* sub, const char* papa)
{
	int ret = 1;
	struct dirent* entry;
	DIR *sub_dir = opendir(sub);
	DIR *papa_dir = opendir(papa);

	if (!sub_dir || !papa_dir) ret = 0;
	else {  
		while ((entry=readdir(sub_dir)) && ret) {
			if (STR_EQUAL(entry->d_name, ".") ||
			    STR_EQUAL(entry->d_name, "..")) continue;
			char new_sub[MAX_PATH];
			char new_papa[MAX_PATH];
			compose_path(new_sub, sub, entry->d_name);
			compose_path(new_papa, papa, entry->d_name);
			if (entry->d_type & DT_REG) {
				ret = is_same_file(new_sub, new_papa);
			} else if (entry->d_type & DT_DIR) {
				ret = is_sub_dir(new_sub, new_papa);
			}
		}
	}

	if (sub_dir) closedir(sub_dir);
	if (papa_dir) closedir(papa_dir);
	return ret;
}

extern "C" {

	int verify_parse_args_1()
	{
		return is_same_file("./case_output", "./case1_output");
	}

	int verify_build_tree_1() 
	{
		return is_same_file("./case_output", "./case2_output");
	}

	int verify_data_integrity_1()
	{
		return is_sub_dir("/mnt", "/");
	}

}
/*
  int main()
  {
  if (is_sub_dir("./haha1", "./haha2")) 
  printf("haha2 contains haha1.\n");
  else
  printf("haha2 does not contain haha1.\n");
  return 0;
  }
*/
